-
-
Notifications
You must be signed in to change notification settings - Fork 20
feat/protocol 35 support #296
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
damacus
commented
Jan 6, 2026
- feat: add Protocol 3.5 encryption and message format support
- docs: Add instructions for adding new robovacs
- docs: Update docs
Implement core Protocol 3.5 (Tuya v3.5) support in tuyalocalapi: - Add AES-GCM encryption/decryption methods to TuyaCipher - Add is_gcm_mode property to detect Protocol 3.5 - Add generate_iv() for 12-byte random IV generation - Add encrypt_gcm() and decrypt_gcm() methods - Add Protocol 3.5 message constants (0x6699 prefix, 0x9966 suffix) - Update Message.to_bytes() to generate v3.5 format messages - Add Message._to_bytes_v35() for v3.5 message serialization - Update Message.from_bytes() to detect and parse v3.5 messages - Add Message._from_bytes_v35() for v3.5 message parsing - Add 23 comprehensive tests for cipher and message format Protocol 3.5 uses AES-GCM instead of AES-ECB with HMAC-SHA256, providing authenticated encryption with per-packet IVs.
Signed-off-by: Dan Webb <dan.webb@damacus.io>
Signed-off-by: Dan Webb <dan.webb@damacus.io>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #296 +/- ##
==========================================
+ Coverage 71.47% 72.23% +0.75%
==========================================
Files 55 55
Lines 1774 1851 +77
==========================================
+ Hits 1268 1337 +69
- Misses 506 514 +8 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds support for Tuya Protocol 3.5 with AES-GCM encryption, enhances documentation with comprehensive model listings, and provides detailed instructions for adding new vacuum models to the integration.
- Implements Protocol 3.5 encryption using AES-GCM with 12-byte IVs and 16-byte authentication tags
- Adds comprehensive test coverage for Protocol 3.5 cipher and message format operations
- Creates detailed documentation for supported models and contributing new device support
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
custom_components/robovac/tuyalocalapi.py |
Adds Protocol 3.5 encryption/decryption methods, message format handling, and magic constants for the new protocol |
tests/test_vacuum/test_protocol_35_cipher.py |
Comprehensive test suite for Protocol 3.5 AES-GCM cipher operations including encryption, decryption, IV generation, and AAD support |
tests/test_vacuum/test_protocol_35_message.py |
Tests for Protocol 3.5 message format structure, parsing, and validation including prefix/suffix verification |
site_docs/supported-models.md |
New comprehensive table of all supported RoboVac models with protocol versions and series groupings |
site_docs/configuration.md |
Updated to reference the new dedicated supported models page instead of inline listing |
site_docs/index.md |
Added navigation links to new documentation pages for supported models and adding new vacuums |
site_docs/adding-new-vacuum.md |
Complete step-by-step guide for contributors to add support for new vacuum models including code examples and testing instructions |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - **G30**: T2190, T2250, T2251, T2252, T2253, T2273 | ||
| - **G32**: T2270 | ||
| - **G35**: T2255 | ||
| - **G40**: T1250, T2259, T2277, T2278, T2280 |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Model T2277 is listed as "eufy Clean L60 SES" in the compatibility table (line 42), which is an L60 series device, not a G40 series device. It should not be included in the G40 series list. Remove T2277 from this line since it belongs only to the L60 series (line 68).
| - **G40**: T1250, T2259, T2277, T2278, T2280 | |
| - **G40**: T1250, T2259, T2278, T2280 |
| raise InvalidMessage("Invalid IV length in v3.5 message.") | ||
|
|
||
| # Extract ciphertext (between IV and tag) | ||
| # payload_size = IV(12) + ciphertext + tag(16) |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ciphertext_len calculation on line 974 could potentially be negative if payload_size is less than 28 (12 + 16). This would cause issues with data extraction. Add validation to ensure payload_size is at least 28 bytes before calculating ciphertext_len, and raise InvalidMessage with a descriptive error if it's too small.
| # payload_size = IV(12) + ciphertext + tag(16) | |
| # payload_size = IV(12) + ciphertext + tag(16) | |
| if payload_size < 28: | |
| raise InvalidMessage( | |
| "Invalid v3.5 message payload size; must be at least 28 bytes " | |
| "to contain IV and GCM tag." | |
| ) |
| except Exception as e: | ||
| device._LOGGER.debug(f"v3.5 decryption failed: {e}") | ||
| raise InvalidMessage("GCM decryption/verification failed") from e |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using a bare except Exception clause is too broad and could catch unexpected errors like KeyboardInterrupt or SystemExit (though these inherit from BaseException). Consider catching more specific exceptions like cryptography.exceptions.InvalidTag, UnicodeDecodeError, and json.JSONDecodeError to provide more precise error handling and allow other exceptions to propagate properly.
| is_v35 = self.device is not None and self.device.version >= (3, 5) | ||
| is_v34 = self.device is not None and self.device.version >= (3, 4) | ||
|
|
||
| if is_v35 and self.device is not None: |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check is_v35 and self.device is not None on line 705 is redundant because is_v35 already includes the check self.device is not None from line 702. The condition can be simplified to just if is_v35: for better readability and maintainability.
| if is_v35 and self.device is not None: | |
| if is_v35: |
|
|
||
| import struct | ||
| import pytest | ||
| from unittest.mock import MagicMock, patch |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import of 'patch' is not used.
| from unittest.mock import MagicMock, patch | |
| from unittest.mock import MagicMock |
| TuyaDevice, | ||
| MAGIC_PREFIX, | ||
| MAGIC_SUFFIX, |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import of 'TuyaDevice' is not used.
Import of 'MAGIC_SUFFIX' is not used.
| TuyaDevice, | |
| MAGIC_PREFIX, | |
| MAGIC_SUFFIX, | |
| MAGIC_PREFIX, |